package com.xinqi.common.base.utils.tree;

import com.google.common.collect.Lists;
import com.xinqi.common.base.utils.lambda.Lambdas;
import org.joor.Reflect;

import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 树形数据帮助类
 *
 * @author linkai
 * @date 2022/11/25
 */
public final class TreeHelp<T, P> {

    private List<T> list;

    private P parent;

    private Comparator<T> comparator;

    private String idField = "id";

    private String parentField = "parent";

    private String childrenField = "children";

    private TreeHelp() {
    }

    public static <T, P> Builder<T, P> builder() {
        return new Builder<>();
    }

    public List<T> handle(P parent) {
        this.parent = parent;
        return handle();
    }

    public List<T> handle() {
        if (list.isEmpty()) {
            return Lists.newArrayList();
        }
        Objects.requireNonNull(parent);
        List<T> root = root();
        Optional.ofNullable(comparator).ifPresent(root::sort);
        handler(root);
        return root;
    }

    private List<T> root() {
        return Lambdas.move(list, v -> Objects.equals(parent, getParent(v)));
    }

    private P getParent(T t) {
        return Reflect.on(t).field(parentField).get();
    }

    private P getId(T t) {
        return Reflect.on(t).field(idField).get();
    }

    private void setChild(T t, List<T> c) {
        Reflect.on(t).set(childrenField, c);
    }

    private void handler(List<T> root) {
        if (root.isEmpty()) {
            return;
        }
        for (T t : root) {
            P p = getId(t);
            List<T> temp = Lambdas.move(list, v -> Objects.equals(p, getParent(v)));
            if (temp.isEmpty()) {
                continue;
            }
            Optional.ofNullable(comparator).ifPresent(temp::sort);
            setChild(t, temp);
            handler(temp);
        }
    }

    public static class Builder<T, P> {

        TreeHelp<T, P> help;

        public Builder() {
            this.help = new TreeHelp<>();
        }

        public Builder<T, P> setComparator(Comparator<T> comparator) {
            this.help.comparator = comparator;
            return this;
        }

        public Builder<T, P> initParent(P parent) {
            this.help.parent = parent;
            return this;
        }

        public Builder<T, P> setList(List<T> s) {
            this.help.list = s;
            return this;
        }

        public Builder<T, P> setId(String id) {
            this.help.idField = id;
            return this;
        }

        public Builder<T, P> setParent(String parent) {
            this.help.parentField = parent;
            return this;
        }

        public Builder<T, P> setChildren(String children) {
            this.help.childrenField = children;
            return this;
        }

        public TreeHelp<T, P> build() {
            Objects.requireNonNull(help.list);
            Objects.requireNonNull(help.idField);
            Objects.requireNonNull(help.parentField);
            Objects.requireNonNull(help.childrenField);
            return help;
        }

    }

}
